﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GLWrapper;
using GameBaseCode;

namespace plane_game
{
    class Program
    {
        static int oldMousx = 0;
        static int oldMousy = 0;
        static float mouseSpeedX = 0.0f;
        static float mouseSpeedY = 0.0f;
        static int mousx = 0;
        static int mousy = 0;

        static int xres = 800;
        static int yres = 600;

        static void Main(string[] args)
        {
            GL.glfwInit();
            GL.glfwOpenWindow(xres, yres, 8, 8, 8, 0, 16, 0, GL.GLFW_WINDOW);

            // Only draw front faces
            GL.glDisable(GL.GL_CULL_FACE);
            //GL.glCullFace(GL.GL_BACK);

            char[] windowTitle = "PLANE GAME LOADING".ToCharArray();
            GL.glfwSetWindowTitle(windowTitle);

            unsafe
            {
                int maxElems = 0;
                GL.glGetIntegerv(GL.GL_MAX_ELEMENTS_INDICES, &maxElems);
                int maxVerts = 0;
                GL.glGetIntegerv(GL.GL_MAX_ELEMENTS_VERTICES, &maxVerts);
                Console.WriteLine("GL_MAX_ELEMENTS_INDICES: " + maxElems);
                Console.WriteLine("GL_MAX_ELEMENTS_VERTICES: " + maxVerts);
            }

            string mediadir = "../../media/";
            Heightmap myHeightmap = new Heightmap(mediadir+"Heightmap.png");
            ObjMesh planeMesh = new ObjMesh(mediadir+"hurricane.obj");
            uint hurricaneTex = SOIL.SOIL_load_OGL_texture(mediadir+"hurricane.jpg", SOIL.SOIL_LOAD_RGBA, 0, 0 );//SOIL.SOIL_FLAG_MIPMAPS)
            if (hurricaneTex == 0)
            {
                throw new Exception("Texture load fail");
            }
            planeMesh.texHandle = hurricaneTex;

            Plane plane = new Plane(myHeightmap);
            plane.mesh = planeMesh;
            plane.position.set(0, 60, 100);


            windowTitle = "PLANE GAME".ToCharArray();
            GL.glfwSetWindowTitle(windowTitle);

            double time = GL.glfwGetTime();
            
            //Frustum myFrustum = new Frustum();
            float fovDegrees = 60.0f;
            float nearDist = 0.5f;
            float farDist = 1800.0f;
            float aspectRatio = (float)(xres / (float)yres);
            //myFrustum.setCamInternals(fovDegrees, aspectRatio, nearDist, farDist);
            
            Camera myCamera = new Camera();
            myCamera.setPosition(300, 300.0f, -300);
            myCamera.setAngle(180.0f * 3.14f / 180.0f, 0.0f);
            myCamera.update(0, 0, 0, 0, 0);
            Vector3 camPos = new Vector3(0, 150, -200);

            GL.glfwSwapInterval(0); // VSync on/off

            int fps = 0;
            double oneSec = GL.glfwGetTime();
            int frames = 0;

            Vector3 force = new Vector3(0, 0, 0);
            Vector3 velocity = new Vector3(0, 0, 0);

            while (GL.glfwGetWindowParam(GL.GLFW_OPENED) != 0)
            {
                pollUserInput();

                double now = GL.glfwGetTime();
                double dt = now - time;
                time = now;

                #region SETUP_3D
                GL.glViewport(0, 0, xres, yres);
                aspectRatio = (float)(xres / (float)yres);

                GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

                GL.glMatrixMode(GL.GL_PROJECTION);
                GL.glLoadIdentity();

                GL.glusPerspective(fovDegrees, aspectRatio, nearDist, farDist);
                GL.glEnable(GL.GL_DEPTH_TEST);
                GL.glDisable(GL.GL_BLEND);

                GL.glMatrixMode(GL.GL_MODELVIEW);
                #endregion

                GL.glDepthFunc(GL.GL_LESS); // nærmere -> tillatt overwrite pixel
                GL.glDepthMask(1);

                #region MOVE_AND_LOAD_CAMERA
                float vx = (GL.glfwGetKey('A') - GL.glfwGetKey('D')) * -50.0f * (float)dt;
                float vy = 0.0f;
                //float vy = (GL.glfwGetKey('W') - GL.glfwGetKey('S')) * -50.0f * (float)dt;
                float vz = (GL.glfwGetKey('W') - GL.glfwGetKey('S')) * -50.0f * (float)dt;
                //float vz = -50 * (float)dt;

                Vector3 newPos = plane.position + plane.getCameraOffset();
                Vector3 lookAtPos = plane.position - (plane.getCameraOffset() + new Vector3(0, 5, 0));
                GL.glTranslate(newPos);
                GL.DrawWireSphere( 2.0f );
                GL.glTranslate(-newPos);
                GL.glTranslate(lookAtPos);
                GL.DrawWireSphere(2.0f);
                GL.glTranslate(-lookAtPos);

                Vector3 delta = camPos - newPos;
                if (delta.Magnitude > 0.000001)
                {
                    // F = -ky

                    // how much of the force goes to horizontal and vertical vectors..
                    force = delta * (1.0f / delta.Magnitude);

                    // helper variable, basically this is the force
                    float intensity = (delta.Magnitude) * 0.5f;// 0.98f; // k =0.5f

                    // apply
                    force = force * intensity;
                    velocity -= force;
                   
                    velocity *= 0.75f;

                    camPos += velocity * (float)dt;
                }


                
                //float tiltCam = (float)GL.glfwGetMouseButton(GL.GLFW_MOUSE_BUTTON_RIGHT);
                //myCamera.update(vx, vy, vz, tiltCam * mouseSpeedX * -0.01f, tiltCam * mouseSpeedY * 0.01f);
                //myCamera.horizontalAng = (float) Math.Atan2(myCamera.getPosition().y - plane.position.y, myCamera.getPosition().x - plane.position.x);
                //myCamera.update(vx, vy, vz, 0, 0);
                myCamera.lookAt( camPos, new Vector3(0, 1, 0), lookAtPos );

                GL.glLoadMatrixf(myCamera.getModelview());
                #endregion

                GL.glShadeModel(GL.GL_SMOOTH);
                GL.glEnableClientState(GL.GL_VERTEX_ARRAY);
                GL.glEnableClientState(GL.GL_COLOR_ARRAY);

                GL.glPushMatrix();
                GL.glTranslatef(0, 400, 0);
                GL.glScalef(700, 800, 700);
                
                float[] kube = {1,1,1,  -1,1,1,  -1,-1,1,  1,-1,1,          // v0-v1-v2-v3 // +Z
                                  1,1,1,  1,-1,1,  1,-1,-1,  1,1,-1,        // v0-v3-v4-v5 // +X
                                  1,1,1,  1,1,-1,  -1,1,-1,  -1,1,1,        // v0-v5-v6-v1 // +Y
                                  -1,1,1,  -1,1,-1,  -1,-1,-1,  -1,-1,1,    // v1-v6-v7-v2 // -X
                                  -1,-1,-1,  1,-1,-1,  1,-1,1,  -1,-1,1,    // v7-v4-v3-v2 // -Y
                                  1,-1,-1,  -1,-1,-1,  -1,1,-1,  1,1,-1};   // v4-v7-v6-v5 // -Z
                float g = 162.0f / 255.0f;
                float b = 232.0f / 255.0f;
                float[] color =  {0,g,b,  0,g,b,  1,1,1,  1,1,1,   // v0-v1-v2-v3
                                  0,g,b,  1,1,1,  1,1,1,  0,g,b,   // v0-v3-v4-v5 +X
                                  0,g,b,  0,g,b,  0,g,b,  0,g,b,   // v0-v5-v6-v1 +Y
                                  0,g,b,  0,g,b,  1,1,1,  1,1,1,   // v1-v6-v7-v2 -X
                                  0,g,b,  0,g,b,  1,1,1,  1,1,1,   // v7-v4-v3-v2 -Y dont care
                                  1,1,1,  1,1,1,  0,g,b,  0,g,b};  // v4-v7-v6-v5 -Z
                unsafe
                {
                    fixed (float* ptr = &color[0])
                        GL.glColorPointer(3, GL.GL_FLOAT, 0, ptr);
                    fixed (float* ptr = &kube[0])
                        GL.glVertexPointer(3, GL.GL_FLOAT, 0, ptr);
                }
                GL.glDrawArrays(GL.GL_QUADS, 0, 24);
                GL.glDisableClientState(GL.GL_VERTEX_ARRAY);
                GL.glDisableClientState(GL.GL_COLOR_ARRAY);
                GL.glPopMatrix();


                GL.glEnable(GL.GL_LIGHTING);
                GL.glEnable(GL.GL_LIGHT0);
                float[] lightPos = { 0.0f, 100.0f, 0.0f, 1.0f };
                GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPos);
                GL.glEnable(GL.GL_COLOR_MATERIAL);
                
                //GL.DrawWireSphere(1.0f);
                myHeightmap.draw();

                float planeRotY = (GL.glfwGetKey(GL.GLFW_KEY_LEFT) - GL.glfwGetKey(GL.GLFW_KEY_RIGHT)) * 3.0f * (float)dt;
                float planeRotX = (GL.glfwGetKey(GL.GLFW_KEY_DOWN) - GL.glfwGetKey(GL.GLFW_KEY_UP)) * 2.0f * (float)dt;
                float planeVz = (GL.glfwGetKey('Z') - GL.glfwGetKey('X')) * 100.0f;
                //if (planeVz != 0.0f)
                {
                    plane.speed = planeVz;
                }
                plane.move(dt);
                plane.update();

                if (planeRotX != 0.0f)
                    plane.rotateX(planeRotX);
                if (planeRotY != 0.0f)
                    plane.rotateY(planeRotY);
       
                plane.draw();

                GL.get_gl_errors();

                #region count_fps
                if (time > oneSec)
                {
                    fps = frames;
                    frames = 0;
                    oneSec = time + 1.0;

                    //Console.WriteLine("fps = " + fps);
                }

                frames++;
                #endregion

                GL.glfwSwapBuffers();

            }
            //GL.glDeleteTextures(textureDictionary.Values.Count, textureDictionary.Values.ToArray());
            GL.glfwTerminate();
        

            //GL.glfwCloseWindow();
        }

        private static void pollUserInput()
        {
            oldMousx = mousx;
            oldMousy = mousy;
            int mx, my;
            unsafe
            {
                GL.glfwGetMousePos(&mx, &my);
            }
            mousx = mx;
            mousy = my;
            mouseSpeedX = mousx - oldMousx;
            mouseSpeedY = mousy - oldMousy;

            int width, height;
            unsafe
            {
                GL.glfwGetWindowSize(&width, &height);
            }
            xres = width; yres = height;
        }


    } // eof Program class
} // eof namespace
